﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using System.Reflection;
using System.Web;
using System.Web.Routing;
using System.Collections;

namespace yc.Site
{
	/// <summary>
	/// 分页控件类 按钮设置接口
	/// </summary>
	public interface IPagerSetting
	{
		/// <summary>
		/// 查询按钮
		/// </summary>
		bool HasSearch { get; }

		/// <summary>
		/// 添加按钮
		/// </summary>
		bool HasCreate { get; }

		/// <summary>
		/// 修改按钮
		/// </summary>
		bool HasEdit { get; }

		/// <summary>
		/// 删除按钮
		/// </summary>
		bool HasDelete { get; }

		/// <summary>
		/// 查看按钮
		/// </summary>
		bool HasDetail { get; }

		/// <summary>
		/// 导出按钮
		/// </summary>
		bool HasExport { get; }
	}

	/// <summary>
	/// 分页控件类 接口
	/// </summary>
	public interface IPager : IList, IPagerSetting
	{
		/// <summary>
		/// 每页显示条数
		/// </summary>
		int PageSize { get; }

		/// <summary>
		/// 当前页
		/// </summary>
		int PageIndex { get; }

		/// <summary>
		/// 总页数
		/// </summary>
		int PageCount { get; }

		/// <summary>
		/// 记录总数
		/// </summary>
		int TotalCount { get; }

		/// <summary>
		/// 页面提交数据
		/// </summary>
		RouteValueDictionary RouteData { get; }

		/// <summary>
		/// 对指定字段排序
		/// </summary>
		/// <param name="fieldName">指定字段</param>
		/// <returns></returns>
		RouteValueDictionary OrderBy(string fieldName);

		/// <summary>
		/// 获取指定字段当前排序状态
		/// </summary>
		/// <param name="fieldName">指定字段</param>
		/// <returns>↓：DESC ↑：ASC 无排序时返回string.Empty</returns>
		string OrderByStatus(string fieldName);

		/// <summary>
		/// 跳转到指定页
		/// </summary>
		/// <param name="index">指定页</param>
		/// <returns></returns>
		RouteValueDictionary Go(int index);

		/// <summary>
		/// 获取页面提交数据
		/// </summary>
		/// <param name="queryStringName">数据名称</param>
		/// <param name="arrayIndex">数据索引</param>
		/// <returns></returns>
		string Get(string queryStringName, int arrayIndex = 0);
	}

	/// <summary>
	/// 分页控件类
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class Pager<T> : List<T>, IPager
	{
		#region 私有属性
		/// <summary>
		/// 页面提交数据
		/// </summary>
		private readonly HttpRequest Request;

		/// <summary>
		/// 默认 每页显示大小 
		/// </summary>
		private readonly int pagesize;

		/// <summary>
		/// 默认 当前页索引 0
		/// </summary>
		private readonly int pageindex;

		/// <summary>
		/// 忽略大小写
		/// </summary>
		private readonly StringComparison ignoreCase;

		/// <summary>
		/// 数据IQueryable对象
		/// </summary>
		private IQueryable<T> source;

		/// <summary>
		/// 当前排序字段
		/// </summary>
		private string orderBy
		{
			get
			{
				var val = Request["orderby"];
				if (!val.Empty())
				{
					if (val.EndsWith("ASC", ignoreCase) || val.EndsWith(" DESC", ignoreCase)) return val;
					return val + " ASC";
				}
				return DefaultOrderBy ?? Properties[0].Name + " ASC";
			}
		}

		/// <summary>
		/// 系统默认排序
		/// </summary>
		public string DefaultOrderBy { set; get; }

		/// <summary>
		/// 页面提交数据
		/// </summary>
		private RouteValueDictionary routeData
		{
			get
			{
				var route = new RouteValueDictionary();
				foreach (string key in Request.QueryString)
				{
					var val = Request.QueryString[key];
					if (val.Empty() || val.Equals(",")) continue;
					route[key] = val;
				}
				foreach (string key in Request.Form)
				{
					var val = Request.Form[key];
					if (val.Empty() || val.Equals(",")) continue;
					route[key] = val;
				}
				if (route.ContainsKey("X-Requested-With")) route.Remove("X-Requested-With");
				if (route.ContainsKey("_")) route.Remove("_");
				return route;
			}
		}
		#endregion

		#region 私有方法
		/// <summary>
		/// 执行过滤数据
		/// </summary>
		/// <returns></returns>
		IQueryable<T> Execute()
		{
			var source = this.source;
			#region Filter
			foreach (var prop in Properties)
			{
				var val = Request[prop.Name];
				if (val.Empty() || val.Equals(",")) continue;
				var valsplit = val.Split(',');

				switch ((Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType).Name)
				{
					case "Boolean":
						source = source.Where(prop.Name + " = @0", bool.Parse(val));
						break;
					case "Int32":
						if (valsplit.Length > 1)
						{
							if (valsplit[0].IsInt()) source = source.Where(prop.Name + " >= @0 ", int.Parse(valsplit[0]));
							if (valsplit[1].IsInt()) source = source.Where(prop.Name + " <= @0 ", int.Parse(valsplit[1]));
						}
						else
						{
							if (valsplit[0].IsInt()) source = source.Where(prop.Name + " = @0 ", int.Parse(valsplit[0]));
						}
						break;
					case "Decimal":
						if (valsplit.Length > 1)
						{
							if (valsplit[0].IsDecimal()) source = source.Where(prop.Name + " >= @0 ", decimal.Parse(valsplit[0]));
							if (valsplit[1].IsDecimal()) source = source.Where(prop.Name + " <= @0 ", decimal.Parse(valsplit[1]));
						}
						else
						{
							if (valsplit[0].IsDecimal()) source = source.Where(prop.Name + " == @0 ", decimal.Parse(valsplit[0]));
						}
						break;
					case "DateTime":
						if (valsplit.Length > 1)
						{
							if (valsplit[0].IsDateTime()) source = source.Where(prop.Name + " >= @0 ", DateTime.Parse(valsplit[0]));
							if (valsplit[1].IsDateTime()) source = source.Where(prop.Name + " <= @0 ", DateTime.Parse(valsplit[1]));
						}
						else
						{
							if (valsplit[0].IsDateTime()) source = source.Where(prop.Name + " == @0 ", DateTime.Parse(valsplit[0]));
						}
						break;
					default:
						source = source.Where(prop.Name + ".Contains(@0)", val);
						break;
				}
			}
			#endregion
			#region Order By
			source = source.OrderBy(orderBy);
			#endregion
			return source;
		}
		#endregion

		#region 初始化
		/// <summary>
		/// 初始化
		/// </summary>
		/// <param name="source"></param>
		/// <param name="defaultOrderBy">默认排序</param>
		public Pager(IQueryable<T> source, string defaultOrderBy = null)
		{
			#region 初始化数据
			this.source = source;
			this.Properties = source.ElementType.GetProperties();
			this.Request = HttpContext.Current.Request;
			this.pagesize = Constants.DefaultPageSize;
			this.pageindex = 1;
			this.ignoreCase = StringComparison.InvariantCultureIgnoreCase;
			this.DefaultOrderBy = defaultOrderBy;
			#endregion

			#region 组织数据
			IQueryable<T> exec = Execute();
			System.Diagnostics.Debug.Write(exec.ToString());
			TotalCount = exec.Count();
			AddRange(exec.Skip(PageSize * (PageIndex - 1)).Take(PageSize).ToList());
			#endregion
		}
		#endregion

		#region 公共方法
		/// <summary>
		/// 对指定字段排序
		/// </summary>
		/// <param name="fieldName">指定字段</param>
		/// <returns></returns>
		public RouteValueDictionary OrderBy(string fieldName)
		{
			var route = routeData;
			var orderSplit = orderBy.Split(' ');
			if (orderSplit[0].Equals(fieldName, ignoreCase) && orderSplit[1].Equals("ASC", ignoreCase)) route["orderby"] = fieldName + " DESC";
			else route["orderby"] = fieldName + " ASC";
			return route;
		}

		/// <summary>
		/// 获取指定字段当前排序状态
		/// </summary>
		/// <param name="fieldName">指定字段</param>
		/// <returns>↓：DESC ↑：ASC 无排序时返回string.Empty</returns>
		public string OrderByStatus(string fieldName)
		{
			if (orderBy.StartsWith(fieldName, ignoreCase))
			{
				if (orderBy.EndsWith(" DESC", ignoreCase)) return "↓";
				if (orderBy.EndsWith(" ASC", ignoreCase)) return "↑";
			}
			return "";
		}

		/// <summary>
		/// 跳转到指定页
		/// </summary>
		/// <param name="index">指定页</param>
		/// <returns></returns>
		public RouteValueDictionary Go(int index)
		{
			var route = routeData;
			route["pageindex"] = index;
			if (index < 1) route.Remove("pageindex");
			return route;
		}

		/// <summary>
		/// 获取页面提交数据
		/// </summary>
		/// <param name="queryStringName">数据名称</param>
		/// <param name="arrayIndex">数据索引</param>
		/// <returns></returns>
		public string Get(string queryStringName, int arrayIndex = 0)
		{
			var res = Request[queryStringName];
			if (res.Empty() || res.Equals(",")) return "";
			var resSplit = res.Split(',');
			if (resSplit.Length > arrayIndex + 1 && resSplit[arrayIndex].Empty()) return "";
			return resSplit[arrayIndex];
		}
		#endregion

		#region 公共属性
		/// <summary>
		/// 要显示的字段
		/// </summary>
		public PropertyInfo[] Properties { get; private set; }

		/// <summary>
		/// 页面提交数据
		/// </summary>
		public RouteValueDictionary RouteData { get { return routeData; } }

		/// <summary>
		/// 数据总行数
		/// </summary>
		public int TotalCount { private set; get; }

		/// <summary>
		/// 每页显示条数
		/// </summary>
		public int PageSize
		{
			get
			{
				var p = Request["pagesize"];
				if (p.IsNatural()) return int.Parse(p);
				return pagesize;
			}
		}

		/// <summary>
		/// 当前页
		/// </summary>
		public int PageIndex
		{
			get
			{
				var p = Request["pageindex"];
				if (p.IsNatural()) return int.Parse(p);
				return pageindex;
			}
		}

		/// <summary>
		/// 总页数
		/// </summary>
		public int PageCount
		{
			get
			{
				var cnt = (TotalCount + PageSize - 1) / PageSize;
				if (cnt < 1) cnt = 1;
				return cnt;
			}
		}

		/// <summary>
		/// 查询按钮
		/// </summary>
		public bool HasSearch { get; private set; }

		/// <summary>
		/// 添加按钮
		/// </summary>
		public bool HasCreate { get; private set; }

		/// <summary>
		/// 修改按钮
		/// </summary>
		public bool HasEdit { get; private set; }

		/// <summary>
		/// 删除按钮
		/// </summary>
		public bool HasDelete { get; private set; }

		/// <summary>
		/// 查看按钮
		/// </summary>
		public bool HasDetail { get; private set; }

		/// <summary>
		/// 导出按钮
		/// </summary>
		public bool HasExport { get; private set; }

		#endregion
	}

	/// <summary>
	/// 分页控件类 静态扩张
	/// </summary>
	public static class PagerExtensions
	{
		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T">对象</typeparam>
		/// <param name="source">数据源</param>
		/// <param name="DefaultOrderBy">默认排序</param>
		/// <returns></returns>
		public static IPager ToPager<T>(this IQueryable<T> source, string defaultOrderBy = null)
		{
			return new Pager<T>(source, defaultOrderBy);
		}
	}
}
